package com.kingwang.study.spring.security.demo.security.repository;

import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.security.web.context.SecurityContextRepository;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * SecurityContextRepository 组合器（组合模式）
 */
public class SecurityContextCompositeRepository implements SecurityContextRepository {
    private List<SecurityContextRepository> repositories = new ArrayList<>();

    public SecurityContextCompositeRepository() {
    }

    public SecurityContextCompositeRepository(List<SecurityContextRepository> repositories) {
        this.repositories = repositories;
    }

    public void addRepository(SecurityContextRepository repo) {
        this.repositories.add(repo);
    }

    public void insertRepositoryBefore(SecurityContextRepository repo,
                                       Class<? extends SecurityContextRepository> beforeRepo) {
        Integer position = getRepoPositionByClass(beforeRepo);

        if (position == null) {
            throw new IllegalArgumentException(beforeRepo.getName() + " 尚未注册");
        }

        this.repositories.add(position, repo);
    }

    private Integer getRepoPositionByClass(Class<?> clazz) {
        while (clazz != null) {
            for (int i = 0; i < this.repositories.size(); i++) {
                if (this.repositories.get(i).getClass().getName().equals(clazz.getName())) {
                    return i;
                }
            }

            clazz = clazz.getSuperclass();
        }

        return null;
    }

    /**
     * 按序加载SecurityContext
     *
     * @param requestResponseHolder
     * @return
     */
    @Override
    public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
        if (this.repositories != null) {
            for (SecurityContextRepository repo : this.repositories) {
                SecurityContext result = repo.loadContext(requestResponseHolder);

                if (result != null) {
                    return result;
                }
            }
        }

        return null;
    }

    /**
     * 按序保存SecurityContext
     *
     * @param securityContext
     * @param request
     * @param response
     */
    @Override
    public void saveContext(SecurityContext securityContext, HttpServletRequest request, HttpServletResponse response) {
        if (this.repositories != null) {
            for (SecurityContextRepository repo : this.repositories) {
                boolean existContext = repo.containsContext(request);

                if (existContext) {
                    repo.saveContext(securityContext, request, response);
                    break;
                }
            }
        }
    }

    /**
     * 按序检查SecurityContext
     *
     * @param request
     * @return
     */
    @Override
    public boolean containsContext(HttpServletRequest request) {
        if (this.repositories != null) {
            for (SecurityContextRepository repo : this.repositories) {
                boolean result = repo.containsContext(request);

                if (result) {
                    return true;
                }
            }
        }

        return false;
    }
}
